using System;
using System.Collections;
using System.Runtime.Serialization;
using Sedna.Core.Support;

namespace Sedna.Core
{
	/// <summary>
	/// Generic Sedna exception
	/// it can contain an Exception code. All exception codes have to be registered in
	/// <see cref="SednaExceptionCodes"/> class.
	/// </summary>
	[Serializable]
	public class SednaException : Exception, ISerializable
	{
		private int exceptionCode=0;

		public int ExceptionCode
		{
			get { return exceptionCode; }
		}

		public SednaException()
		{
		}

		public SednaException(string message) : base(message)
		{
		}

		public SednaException(string message, Exception exInner) : base(message, exInner)
		{
		}

		public SednaException(int exceptionCode): base("Exception code: "+exceptionCode)
		{
			this.exceptionCode=exceptionCode;
		}

		public SednaException(int exceptionCode, string message) : base("Exception code: "+exceptionCode+" Message:"+message)
		{
			this.exceptionCode=exceptionCode;
		}

		public SednaException(int exceptionCode, Exception exInner): this(exceptionCode, "", exInner)
		{
		}

		public SednaException(int exceptionCode, string message, Exception exInner) : base("Exception code: "+exceptionCode+" Message:"+message, exInner)
		{
			this.exceptionCode=exceptionCode;
		}

        public SednaException(SerializationInfo info, StreamingContext context) : base (info, context)
        {
            exceptionCode = info.GetInt32("ExceptionCode");
        }
	    
	    
	    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
	    {
            base.GetObjectData(info, context);
            info.AddValue("ExceptionCode", ExceptionCode);
        }
	    
	    
	    public static Exception ExtractInnerException(Exception exception, Type targetType)
	    {
	        Assert.IsTrue(typeof(Exception).IsAssignableFrom(targetType), "Target type must be a subclass of Exception");
	        while (exception!=null)
	        {
	            if (targetType.IsAssignableFrom(exception.GetType()))
	            {
                    return exception;
	            }
                exception = exception.InnerException;
	        }
            return null;
	    }

        public static Exception ExtractInnerException(Exception exception, IList skipExTypes)
        {
            while (exception != null)
            {
                if (skipExTypes == null || !skipExTypes.Contains(exception.GetType()))
                {
                    return exception;
                }
                exception = exception.InnerException;
            }
            return null;
        }
    }
}
